﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MugenInjection.Exceptions;
using MugenInjection.Infrastructure;
using MugenInjection.Interface;
using MugenInjection.Web.Interface;

namespace MugenInjection.Web.Settings
{
    /// <summary>
    /// The default <see cref="IApplicationConfiguration"/> implementation.
    /// </summary>
    public class ApplicationConfiguration : IApplicationConfiguration
    {
        #region Fields

        private readonly IInjector _injector;
        private readonly List<IConfiguration> _configurations = new List<IConfiguration>();

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ApplicationConfiguration"/> class.
        /// </summary>
        public ApplicationConfiguration(IInjector injector)
        {
            Validate.ArgumentNotNull(injector, "injector");
            _injector = injector;
            Configurations = new ReadOnlyCollection<IConfiguration>(_configurations);
        }

        #endregion

        #region Implementation of IApplicationConfiguration

        /// <summary>
        /// Gets or sets the <see cref="IInjector"/> that is used in the application.
        /// </summary>
        public IInjector Injector
        {
            get { return _injector; }
        }

        /// <summary>
        /// Gets all current configurations.
        /// </summary>
        public ReadOnlyCollection<IConfiguration> Configurations { get; private set; }

        /// <summary>
        /// Adds the specified <see cref="IConfiguration"/>.
        /// </summary>
        /// <param name="configuration">The specified <see cref="IConfiguration"/>.</param>
        public void AddConfiguration(IConfiguration configuration)
        {
            Validate.ArgumentNotNull(configuration, "configuration");
            var type = configuration.GetType();
            if (_configurations.Contains(configuration) || _configurations.Any(c => c.GetType() == type))
                throw new InvalidSettingException("Duplicate settings.");
            _configurations.Add(configuration);
            configuration.Load(this);
        }

        /// <summary>
        /// Removes the specified <see cref="IConfiguration"/>.
        /// </summary>
        /// <param name="configuration">The specified <see cref="IConfiguration"/>.</param>
        public void RemoveConfiguration(IConfiguration configuration)
        {
            Validate.ArgumentNotNull(configuration, "configuration");
            if (!Configurations.Contains(configuration))
                throw new InvalidSettingException("Configuration instance not found in current ApplicationConfiguration.");
            configuration.Unload(this);
            _configurations.Remove(configuration);
        }

        /// <summary>
        /// Occured when the application is starting.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> ApplicationStarting;

        /// <summary>
        /// Occured when the application is started.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> ApplicationStarted;

        /// <summary>
        /// Occured when the application is stopped.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> ApplicationStopped;

        /// <summary>
        /// Handles the Start event of the Session.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> SessionStart;

        /// <summary>
        /// Occured when the session is ended.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> SessionEnd;

        /// <summary>
        /// Handles the BeginRequest event of the Application.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> BeginRequest;

        /// <summary>
        /// Occured when the request is ended.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> EndRequest;

        /// <summary>
        /// Handles the AuthenticateRequest event of the Application.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> AuthenticateRequest;

        /// <summary>
        /// Handles the Error event of the Application.
        /// </summary>
        public event Action<MugenInjectionHttpApplication> ApplicationError;

        #endregion

        #region Events

        public void OnApplicationStarting(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = ApplicationStarting;
            if (handler != null) handler(application);
        }

        public void OnApplicationStarted(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = ApplicationStarted;
            if (handler != null) handler(application);
        }

        public void OnApplicationStopped(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = ApplicationStopped;
            if (handler != null) handler(application);
        }

        public void OnSessionStart(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = SessionStart;
            if (handler != null) handler(application);
        }

        public void OnSessionEnd(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = SessionEnd;
            if (handler != null) handler(application);
        }

        public void OnBeginRequest(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = BeginRequest;
            if (handler != null) handler(application);
        }

        public void OnEndRequest(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = EndRequest;
            if (handler != null) handler(application);
        }

        public void OnAuthenticateRequest(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = AuthenticateRequest;
            if (handler != null) handler(application);
        }

        public void OnApplicationError(MugenInjectionHttpApplication application)
        {
            Action<MugenInjectionHttpApplication> handler = ApplicationError;
            if (handler != null) handler(application);
        }

        #endregion

        #region Implementation of IDisposable

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            if (_injector != null)
                _injector.Dispose();
        }

        #endregion
    }
}